/*
* This file is a part of the open-eBackup project.
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
* If a copy of the MPL was not distributed with this file, You can obtain one at
* http://mozilla.org/MPL/2.0/.
*
* Copyright (c) [2024] Huawei Technologies Co.,Ltd.
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*/
#include "DiskScannerHandler.h"
#include "securec.h"
#include "error.h"
#include "system/System.hpp"
#include "common/Utils.h"
#include "common/utils/Utils.h"
#include "common/JsonUtils.h"
#include "log/Log.h"
#include "common/Constants.h"
#include "common/Macros.h"
#include "volume_handlers/common/DiskCommDef.h"
#include "volume_handlers/common/ControlDevice.h"
#include "volume_handlers/common/StorageDataType.h"
#include "curl_http/HttpClientInterface.h"
#include "common/utils/Utils.h"

namespace {
const std::string MODULE_NAME = "DiskScannerHandler";
const std::string SUDO_DISK_TOOL_PATH = VirtPlugin::VIRT_PLUGIN_PATH + "bin/security_sudo_disk.sh";
const std::string ISCSI_TARGET_PORT = "3260";
const std::string DISK_HEAD = "/dev/";
const std::string MAX_UPRESCAN_TIMEOUT = "1800"; // 1800 second
const std::string D_FINDDISK = "../";
const std::string INTERNAL_BACKUP_SCENCE = "1";
const int32_t NAA_POS_OFFSET = 4;
const int32_t WAIT_RESCAN_TIME = 5;
const int32_t LUN_ID_TO_ASCII_OFFSET = 20;
const int32_t BASE_URL_SPLIT = 2;
const int32_t DETACH_VOLUME_MAX_RETRY_TIMES = 5;
const int32_t FILE_BUFF_SIZE = 1024;
const int32_t WWN_POS_OFFSET = 6;
const int32_t MAX_CYCLE_NUM = 2;
const int32_t MULTIPLE = 2;
const int32_t PAGE_LEN_IDX = 7;
const int32_t BINARY_TO_ASCII_LEN = 8;
const int32_t LUN_ID_TO_ASCII_LEN = 9;
const int32_t CMD_OFFSET = 2;
const int32_t TRD_OFFSET = 3;
const int32_t NEXT_OFFSET = 4;
const int32_t DEFAULT_VAL = 255;
const int32_t DEC_A = 10;
const int32_t DEC_B = 11;
const int32_t DEC_C = 12;
const int32_t DEC_D = 13;
const int32_t DEC_E = 14;
const int32_t DEC_F = 15;
const int32_t HEX_NUM = 16;
const int32_t SESSION_STATUS_NUM = 3;
const int32_t NUM_2 = 2;
const char ASCII_BASE = 48;
using Defer = std::shared_ptr<void>;
const std::string AGENT_INSTALL_TYPE_INTERNAL = "1";
const std::string DISTRIBUTE_DEPLOY_TYPE = "d7";
const std::string BACKUP_NET_PLANE = "backup";
const std::string STORAGE_NET_PLANE = "storage";
const std::vector<std::string> SUPPORT_IP_RULE_TYPE = {
    "backup",
    "storage",
    "archive",
    "replication"
};
}

namespace VirtPlugin {
static std::atomic<bool> g_installedUltr(false);
std::mutex g_scanLunMutex;
std::condition_variable g_scanlunEndCond;
static std::atomic<int> g_rescanLunState((int)NOT_RUN_UPRESCAN);
static std::once_flag onceFlag;
std::string DiskScannerHandler::m_hostUuid;
void SetScanState(UP_RESCAN_STATE_E state)
{
    g_rescanLunState = state;
}

int GetScanState()
{
    return static_cast<int>(g_rescanLunState);
}
DiskScannerHandler *DiskScannerHandler::GetInstance()
{
    static DiskScannerHandler instance;
    std::call_once(onceFlag, [&]() {
        if (instance.GetHostUuid(DiskScannerHandler::m_hostUuid) != SUCCESS) {
            instance.GetHostSN(DiskScannerHandler::m_hostUuid);
        }
    });
    return &instance;
}

DiskScannerHandler::DiskScannerHandler()
{}

DiskScannerHandler::~DiskScannerHandler()
{}

/**
 *  @brief 获取当前主机节点的UUID
 *
 *  @param hostUuid   [OUT]本机uuid
 *  @return 成功返回 SUCCESS，出错返回 Module::FAILED
 */
int32_t DiskScannerHandler::GetHostUuid(std::string &hostUuid)
{
    std::vector<std::string> cmdOut;
    std::string agentHomedir = Module::EnvVarManager::GetInstance()->GetAgentHomePath();
    std::vector<Module::CmdParam> cmdParam {
        Module::CmdParam(Module::COMMON_CMD_NAME, "sudo"),
        Module::CmdParam(Module::SCRIPT_CMD_NAME, agentHomedir + SUDO_DISK_TOOL_PATH),
        "get_host_uuid"
    };
    if (Utils::CallAgentExecCmd(cmdParam, cmdOut) != 0) {
        ERRLOG("Get host uuid failed, ret:");
        return Module::FAILED;
    } else if (cmdOut.size() > 0) {
        hostUuid = cmdOut[0];
        WARNLOG("host uuid:%s", hostUuid.c_str());
        return Module::SUCCESS;
    }
    ERRLOG("Get host uuid count is 0. ");
    return Module::FAILED;
}

// 内置时无法使用dmidecode，用设定的SN替代UUID
int32_t DiskScannerHandler::GetHostSN(std::string &hostSN)
{
    std::vector<std::string> cmdOut;
    std::string agentHomedir = Module::EnvVarManager::GetInstance()->GetAgentHomePath();
    std::vector<Module::CmdParam> cmdParam {
        Module::CmdParam(Module::COMMON_CMD_NAME, "sudo"),
        Module::CmdParam(Module::SCRIPT_CMD_NAME, agentHomedir + SUDO_DISK_TOOL_PATH),
        "get_host_sn"
    };
    if (Utils::CallAgentExecCmd(cmdParam, cmdOut) != 0 || cmdOut.empty()) {
        WARNLOG("Get login target ip failed.");
        return FAILED;
    }

    hostSN = cmdOut[0];
    INFOLOG("Get the host uuid success: %s.", hostSN.c_str());
    return SUCCESS;
}

std::string DiskScannerHandler::GetHostUuid() const
{
    return m_hostUuid;
}

/**
 *  @brief 判断当前主机节点的是否安装iscsi启动器
 *
 *  @return 安装返回 SUCCESS，未安装返回 Module::FAILED
 */
bool DiskScannerHandler::IsInstallIscsiInitiator()
{
    std::vector<std::string> cmdOut;
    std::string agentHomedir = Module::EnvVarManager::GetInstance()->GetAgentHomePath();
    std::vector<Module::CmdParam> cmdParam {
        Module::CmdParam(Module::COMMON_CMD_NAME, "sudo"),
        Module::CmdParam(Module::SCRIPT_CMD_NAME, agentHomedir + SUDO_DISK_TOOL_PATH),
        "check_iscsi_exist"
    };
    if (Utils::CallAgentExecCmd(cmdParam, cmdOut) != 0) {
        ERRLOG("The iSCSI initiator is not installed on the current host or the iSCSI service is not started.");
        return false;
    }
    return true;
}

/**
 *  @brief 获取当前主机节点上的Iscsi Initor IQN
 *
 *  @param iqnNumber   [OUT]本机IQN
 *  @return 成功返回 SUCCESS，出错返回 Module::FAILED
 */
int32_t DiskScannerHandler::GetIscsiInitor(std::string &iqnNumber)
{
    std::vector<std::string> cmdOut;
    std::string agentHomedir = Module::EnvVarManager::GetInstance()->GetAgentHomePath();
    Defer _(nullptr, [&](...) {
        Module::FreeContainer(cmdOut);
    });
    std::vector<Module::CmdParam> cmdParam {
        Module::CmdParam(Module::COMMON_CMD_NAME, "sudo"),
        Module::CmdParam(Module::SCRIPT_CMD_NAME, agentHomedir + SUDO_DISK_TOOL_PATH),
        "get_iscsi_iqn"
    };
    if (Utils::CallAgentExecCmd(cmdParam, cmdOut) != 0) {
        ERRLOG("Get iscsi initiator id failed.");
        return Module::FAILED;
    } else if (cmdOut.size() > 0) {
        iqnNumber = cmdOut[0];
        return Module::SUCCESS;
    }
    ERRLOG("Get iscsi initiator id count is 0. ");
    return Module::FAILED;
}

int32_t DiskScannerHandler::AddTypeIpRulePolicy(const std::string &targetIP, const std::string &targetType)
{
    if (targetIP.empty()) {
        ERRLOG("Parameter is invalid, dest ip is empty.");
        return Module::FAILED;
    }
    if (std::find(SUPPORT_IP_RULE_TYPE.begin(), SUPPORT_IP_RULE_TYPE.end(), targetType) ==
        SUPPORT_IP_RULE_TYPE.end()) {
        ERRLOG("Unsupport ip rule type: %s.", targetType.c_str());
        return Module::FAILED;
    }
    UpdateIpRoutePolicyRequest req;
    req.SetTaskType(targetType);
    req.SetDestIp(targetIP);
    OpenStorageApiClient apiClient;
    std::shared_ptr<UpdateIpRoutePolicyResponse> response = apiClient.AddIpPolicy(req);
    if (response == nullptr) {
        ERRLOG("AddIpPolicy failed, null response handler returned.");
        return Module::FAILED;
    }
    int64_t errCode = response->GetErrorCode();
    if (errCode != Module::SUCCESS) {
        ERRLOG("AddIpPolicy failed, error code: %ld.", errCode);
        return Module::FAILED;
    }
    INFOLOG("AddIscsiLogicIpRoutePolicy success.");
    return Module::SUCCESS;
}

int32_t DiskScannerHandler::AddIscsiLogicIpRoutePolicy(const std::string &targetIP)
{
    DBGLOG("Enter");
    std::string deployType;
    int32_t ret = Utils::GetDeployType(deployType);
    if (ret == SUCCESS && deployType == DISTRIBUTE_DEPLOY_TYPE) {
        WARNLOG("Deployed in distribute storage, no need to add route policy.");
        return SUCCESS;
    }
    std::string deployScence;
    ret = Utils::GetAgentDeployScence(deployScence);
    if (ret != SUCCESS) {
        WARNLOG("Failed to get agent scence.");
    }
    bool isInternalScence = deployScence == AGENT_INSTALL_TYPE_INTERNAL;
    if (!isInternalScence) {
        INFOLOG("Not internal agent, no need to add ip policy.");
        return Module::SUCCESS;
    }
    if ((AddTypeIpRulePolicy(targetIP, BACKUP_NET_PLANE) &
        AddTypeIpRulePolicy(targetIP, STORAGE_NET_PLANE)) != Module::SUCCESS) { // 位运算判断
        ERRLOG("AddTypeIpRulePolicy for ip(%s) failed.", targetIP.c_str());
        return Module::FAILED;
    }
    return Module::SUCCESS;
}

int32_t DiskScannerHandler::DiscoveryIscsiTarget(const std::string &targetIP, std::string &iqnAddress)
{
    DBGLOG("Target address is connectable, ip:%s", targetIP.c_str());
    std::vector<std::string> cmdOut;
    std::string agentHomedir = Module::EnvVarManager::GetInstance()->GetAgentHomePath();
    std::vector<Module::CmdParam> cmdParam {
        Module::CmdParam(Module::COMMON_CMD_NAME, "sudo"),
        Module::CmdParam(Module::SCRIPT_CMD_NAME, agentHomedir + SUDO_DISK_TOOL_PATH),
        "discovery_iscsi_target",
        Module::CmdParam(Module::COMMON_PARAM, targetIP)
    };
    if (Utils::CallAgentExecCmd(cmdParam, cmdOut) != 0 || cmdOut.size() == 0) {
        ERRLOG("Discovery target failed, target ip:%s", targetIP.c_str());
        return Module::FAILED;
    }
    int n = cmdOut[0].size();
    for (int i = 0; i < n; i++) {
        if (cmdOut[0][i] == ' ') {
            iqnAddress = cmdOut[0].substr(i + 1, n - i - 1);
        }
    }
    return Module::SUCCESS;
}

/**
 *  @brief 发现并登陆目标器
 *
 *  @param targetIP [IN] target ip
 *  @return 成功返回 SUCCESS，出错返回 Module::FAILED
 */
int32_t DiskScannerHandler::LoginIscsiTarget(const std::string &targetIP)
{
    AddIscsiLogicIpRoutePolicy(targetIP);
    if (TestConnect(targetIP) != Module::SUCCESS) {
        ERRLOG("Target address is unreachable, target ip:%s", targetIP.c_str());
        return Module::FAILED;
    }
    // 先登出残留的会话，再重新建立连接
    LogOutTarget(targetIP);
    std::string iqnAddress;
    if (DiscoveryIscsiTarget(targetIP, iqnAddress) != Module::SUCCESS) {
        ERRLOG("Failed to discover target, target ip:%s", targetIP.c_str());
        return Module::FAILED;
    }
    std::vector<std::string> cmdOut;
    std::string agentHomedir = Module::EnvVarManager::GetInstance()->GetAgentHomePath();
    std::vector<Module::CmdParam> cmdParam = {
        Module::CmdParam(Module::COMMON_CMD_NAME, "sudo"),
        Module::CmdParam(Module::SCRIPT_CMD_NAME, agentHomedir + SUDO_DISK_TOOL_PATH),
        "login_iscsi_target",
        Module::CmdParam(Module::COMMON_PARAM, iqnAddress),
        Module::CmdParam(Module::COMMON_PARAM, targetIP)
    };
    int ret = Utils::CallAgentExecCmd(cmdParam, cmdOut);

    bool logined = (ret == 0) || (cmdOut.size() > 0 &&
                    cmdOut.begin()->find("1 session requested, but 1 already present") != std::string::npos);
    if (!logined) {
        ERRLOG("Login target failed, return error is:%d", ret);
    } else {
        ret = Module::SUCCESS;
        INFOLOG("Login target ip success, ip:%s", targetIP.c_str());
    }
    return ret;
}

int32_t DiskScannerHandler::LogOutTarget(const std::string &targetIp)
{
    INFOLOG("Start to logout the target, its ip is %s.", targetIp.c_str());
    std::string agentHomedir = Module::EnvVarManager::GetInstance()->GetAgentHomePath();
    std::vector<std::string> cmdOut;
    std::vector<Module::CmdParam> cmdParam{
        Module::CmdParam(Module::COMMON_CMD_NAME, "sudo"),
        Module::CmdParam(Module::SCRIPT_CMD_NAME, agentHomedir + SUDO_DISK_TOOL_PATH),
        "logout_iscsi_target",
        Module::CmdParam(Module::COMMON_PARAM, targetIp)
    };
    if (Utils::CallAgentExecCmd(cmdParam, cmdOut) != 0) {
        ERRLOG("Failed to logout the target.");
        return FAILED;
    }
    INFOLOG("Do logout action sucess.");
    return SUCCESS;
}

int32_t DiskScannerHandler::TestConnect(const std::string &targetIP)
{
    std::vector<std::string> cmdOut;
    std::string agentHomedir = Module::EnvVarManager::GetInstance()->GetAgentHomePath();
    std::vector<Module::CmdParam> cmdParam {
        Module::CmdParam(Module::COMMON_CMD_NAME, "sudo"),
        Module::CmdParam(Module::SCRIPT_CMD_NAME, agentHomedir + SUDO_DISK_TOOL_PATH),
        "check_ip_connect",
        Module::CmdParam(Module::COMMON_PARAM, targetIP)
    };
    if (Utils::CallAgentExecCmd(cmdParam, cmdOut) != 0) {
        WARNLOG("Test connect failed, target ip:%s", targetIP.c_str());
        return Module::FAILED;
    }
    return Module::SUCCESS;
}

/**
 *  @brief 获取当前主机节点上的FC Initor WWPN
 *
 *  @param vecWWPN   [OUT] WWPN
 *  @return 成功返回 SUCCESS，出错返回 Module::FAILED
 */
int32_t DiskScannerHandler::GetFCInitor(std::vector<std::string> &vecWWPN)
{
    std::vector<std::string> cmdOut;
    std::string agentHomedir = Module::EnvVarManager::GetInstance()->GetAgentHomePath();
    std::vector<Module::CmdParam> cmdParam {
        Module::CmdParam(Module::COMMON_CMD_NAME, "sudo"),
        Module::CmdParam(Module::SCRIPT_CMD_NAME, agentHomedir + SUDO_DISK_TOOL_PATH),
        "get_fc_initor"
    };
    if (Utils::CallAgentExecCmd(cmdParam, cmdOut) != 0) {
        WARNLOG("Get fc initiator id failed.");
        return Module::FAILED;
    }
    if (cmdOut.size() == 0) {
        ERRLOG("Get fc initiator id count is 0. ");
        return Module::FAILED;
    }
    for (std::vector<std::string>::iterator ite = cmdOut.begin(); cmdOut.end() != ite; ++ite) {
        std::string tmpString = *ite;
        boost::replace_all(tmpString, "0x", "");
        vecWWPN.push_back(tmpString);
    }
    return Module::SUCCESS;
}

/**
 *  @brief 获取当前主机节点上的已登录的TargetIP
 *
 *  @param vecTargetIP   [OUT] IP
 *  @return 成功返回 SUCCESS，出错返回 Module::FAILED
 */
int32_t DiskScannerHandler::GetLoginedTargetIP(std::vector<std::string> &vecTargetIP)
{
    std::vector<std::string> cmdOut;
    std::string agentHomedir = Module::EnvVarManager::GetInstance()->GetAgentHomePath();
    std::vector<Module::CmdParam> cmdParam {
        Module::CmdParam(Module::COMMON_CMD_NAME, "sudo"),
        Module::CmdParam(Module::SCRIPT_CMD_NAME, agentHomedir + SUDO_DISK_TOOL_PATH),
        "get_loggedIn_targetIp"
    };
    if (Utils::CallAgentExecCmd(cmdParam, cmdOut) != 0) {
        WARNLOG("Get login target ip error.");
        return Module::FAILED;
    }
    if (cmdOut.size() == 0) {
        WARNLOG("Logined target ip count is 0. ");
        return Module::SUCCESS;
    }
    for (std::vector<std::string>::iterator ite = cmdOut.begin(); cmdOut.end() != ite; ++ite) {
        vecTargetIP.push_back(*ite);
        DBGLOG("Get logined target ip: %s", (*ite).c_str());
    }
    return Module::SUCCESS;
}

int32_t DiskScannerHandler::GetIscsiSessionStatus(std::vector<IscsiSessionStatus> &sessionStatusList)
{
    std::vector<std::string> cmdOut;
    std::string agentHomedir = Module::EnvVarManager::GetInstance()->GetAgentHomePath();
    std::vector<Module::CmdParam> cmdParam {
        Module::CmdParam(Module::COMMON_CMD_NAME, "sudo"),
        Module::CmdParam(Module::SCRIPT_CMD_NAME, agentHomedir + SUDO_DISK_TOOL_PATH),
        "get_iscsi_session_status"
    };
    if (Utils::CallAgentExecCmd(cmdParam, cmdOut) != 0) {
        WARNLOG("Get login target ip error.");
        return Module::FAILED;
    }
    if (cmdOut.size() == 0 || cmdOut.size() % SESSION_STATUS_NUM != 0) {
        WARNLOG("Get iscsi session count is %d.", cmdOut.size());
        return Module::FAILED;
    }
    for (int32_t i = 0; i <= cmdOut.size() - SESSION_STATUS_NUM; i += SESSION_STATUS_NUM) {
        IscsiSessionStatus status(cmdOut[i], cmdOut[i + 1], cmdOut[i + NUM_2]);
        sessionStatusList.push_back(status);
    }
    INFOLOG("Get iscsi session status success.");
    return Module::SUCCESS;
}

int32_t DiskScannerHandler::DoScanAfterAttach(const std::string &volId, const std::string &volWwn,
    std::string &objPath, bool useIscsi)
{
    std::string deployScence;
    Utils::GetAgentDeployScence(deployScence);
    m_isInternalScence = deployScence == INTERNAL_BACKUP_SCENCE;

    if (m_isInternalScence) {
        objPath = GetDiskPathForWwnInSysDir(volWwn);
    } else {
        objPath = ScanDiskPreare(volId, volWwn);
    }
    
    if (!objPath.empty()) {
        INFOLOG("Get path success after preare, objPath:%s", objPath.c_str());
        return Module::SUCCESS;
    }
    // 使用重试锁，防止其他子任务已扫描出目标盘符，而此处仍在等待重试扫盘
    if (!m_Mutext.try_lock()) {
        WARNLOG("Scan disk try lock failed, wait next retry.");
        return Module::FAILED;
    }
    Defer _(nullptr, [&](...) {
        m_Mutext.unlock();
    });
    INFOLOG("Start to scan disk for wwn:%s.", volWwn.c_str());
    SetScanState(RUNNING_UPRESCAN);
    if (useIscsi) {
        RescanIscsiDisk();
    } else {
        RescanFCDisk();
    }
    SetScanState(RUNNED_UPRESCAN);
    std::unique_lock<std::mutex> lock(g_scanLunMutex);
    g_scanlunEndCond.notify_all();
    
    if (m_isInternalScence) {
        objPath = GetDiskPathForWwnInSysDir(volWwn);
    } else {
        objPath = GetDiskPath(volId, volWwn);
    }
    if (objPath.empty()) {
        ERRLOG("Do scan get disk path failed, wwn:%s", volWwn.c_str());
        return Module::FAILED;
    }
    INFOLOG("Leave scan after attach, wwn:%s, path:%s", volWwn.c_str(), objPath.c_str());
    return Module::SUCCESS;
}

int32_t DiskScannerHandler::RescanFCDisk()
{
    if (g_installedUltr) {
        INFOLOG("UltraPath is installed, rescan disk by ultratool.");
        return ScanUseUpRescan();
    }
    return ScanFCHost();
}

int32_t DiskScannerHandler::RescanIscsiDisk()
{
    if (g_installedUltr) {
        INFOLOG("UltraPath is installed, rescan disk by ultratool.");
        return ScanUseUpRescan();
    }
    RescanIscsiSession();
    return ScanScsiHost();
}

// 使用多路径扫盘
int32_t DiskScannerHandler::ScanUseUpRescan()
{
    std::string agentHomedir = Module::EnvVarManager::GetInstance()->GetAgentHomePath();
    std::vector<std::string> cmdOut;
    std::vector<Module::CmdParam> cmdParam {
        Module::CmdParam(Module::COMMON_CMD_NAME, "sudo"),
        Module::CmdParam(Module::SCRIPT_CMD_NAME, agentHomedir + SUDO_DISK_TOOL_PATH),
        "do_uprescan"
    };
    int runResult = Utils::CallAgentExecCmd(cmdParam, cmdOut);
    if (runResult != SUCCESS) {
        ERRLOG("Run uprescan failed, errno[%d]:[%s]", errno, strerror(errno));
        return FAILED;
    }
    DBGLOG("Uprescan success.");
    return SUCCESS;
}

// 扫描所有SCSI主机总线
int32_t DiskScannerHandler::ScanFCHost()
{
    std::string agentHomedir = Module::EnvVarManager::GetInstance()->GetAgentHomePath();
    std::vector<std::string> cmdOut;
    std::vector<Module::CmdParam> cmdParam {
        Module::CmdParam(Module::COMMON_CMD_NAME, "sudo"),
        Module::CmdParam(Module::SCRIPT_CMD_NAME, agentHomedir + SUDO_DISK_TOOL_PATH),
        "scan_fc_host"
    };
    int runResult = Utils::CallAgentExecCmd(cmdParam, cmdOut);
    if (runResult != SUCCESS) {
        ERRLOG("Scan fc host faied.");
        return FAILED;
    }
    DBGLOG("Scan fc host success.");
    return SUCCESS;
}

// 扫描所有的SCSI总线设备
int32_t DiskScannerHandler::ScanScsiHost()
{
    std::string agentHomedir = Module::EnvVarManager::GetInstance()->GetAgentHomePath();
    std::vector<std::string> cmdOut;
    std::vector<Module::CmdParam> cmdParam {
        Module::CmdParam(Module::COMMON_CMD_NAME, "sudo"),
        Module::CmdParam(Module::SCRIPT_CMD_NAME, agentHomedir + SUDO_DISK_TOOL_PATH),
        "scan_scsi_host"
    };
    int runResult = Utils::CallAgentExecCmd(cmdParam, cmdOut);
    if (runResult != SUCCESS) {
        ERRLOG("Scan scsi host faied.");
        return FAILED;
    }
    DBGLOG("Scan scsi host success.");
    return SUCCESS;
}

std::string DiskScannerHandler::GetDiskPathForWwnInSysDir(const std::string &volWwn)
{
    INFOLOG("Start to get disk path for wwn in inner scence %s.", volWwn.c_str());
    std::set<std::string> diskLetters;
    std::string diskPath = "";

    int32_t ret = GetAllDiskLetters(diskLetters);
    if (ret != SUCCESS) {
        ERRLOG("Failed to get all disk letters.");
        return diskPath;
    }

    for (const std::string &diskLetter : diskLetters) {
        std::string diskWwn;
        if (GetIscsiDiskWwid(diskLetter, diskWwn) != SUCCESS) {
            DBGLOG("Jump no scsi device %s.", diskLetter.c_str());
            continue;
        }
        if (diskWwn == volWwn) {
            INFOLOG("Find the target disk wwn in the environment.");
            diskPath = DISK_HEAD + diskLetter;
            return diskPath;
        }
    }

    ERRLOG("Get the disk wwn in sysDir Failed.");
    return diskPath;
}

int32_t DiskScannerHandler::GetAllDiskLetters(std::set<std::string> &diskLetters)
{
    std::vector<std::string> cmdOut;
    std::string agentHomedir = Module::EnvVarManager::GetInstance()->GetAgentHomePath();
    std::vector<Module::CmdParam> cmdParam {
        Module::CmdParam(Module::COMMON_CMD_NAME, "sudo"),
        Module::CmdParam(Module::SCRIPT_CMD_NAME, agentHomedir + SUDO_DISK_TOOL_PATH),
        "get_all_disk_letter"
    };
    if (Utils::CallAgentExecCmd(cmdParam, cmdOut) != 0) {
        WARNLOG("Failed to get all disk letters.");
        return FAILED;
    }
    for (const auto &buff : cmdOut) {
        diskLetters.insert(buff);
    }

    INFOLOG("Get all disk letters success.");
    return SUCCESS;
}

int32_t DiskScannerHandler::GetIscsiDiskWwid(const std::string &diskLetter, std::string &diskWwn)
{
    std::vector<std::string> cmdOut;
    std::string agentHomedir = Module::EnvVarManager::GetInstance()->GetAgentHomePath();
    std::vector<Module::CmdParam> cmdParam {
        Module::CmdParam(Module::COMMON_CMD_NAME, "sudo"),
        Module::CmdParam(Module::SCRIPT_CMD_NAME, agentHomedir + SUDO_DISK_TOOL_PATH),
        "get_disk_wwn_by_wwid",
        Module::CmdParam(Module::COMMON_PARAM, diskLetter),
    };
    if (Utils::CallAgentExecCmd(cmdParam, cmdOut) != 0 || cmdOut.empty()) {
        DBGLOG("The disk has no wwn, will jump over.");
        return FAILED;
    }

    diskWwn = cmdOut[0].substr(NAA_POS_OFFSET);
    DBGLOG("Get disk wwn success, the wwn is %s.", diskWwn.c_str());
    return SUCCESS;
}

void DiskScannerHandler::RescanIscsiSession()
{
    DBGLOG("Start to scan disk for iscsi");
    sleep(WAIT_RESCAN_TIME);

    std::vector<std::string> cmdOut;
    std::string agentHomedir = Module::EnvVarManager::GetInstance()->GetAgentHomePath();
    std::vector<Module::CmdParam> cmdParam {
        Module::CmdParam(Module::COMMON_CMD_NAME, "sudo"),
        Module::CmdParam(Module::SCRIPT_CMD_NAME, agentHomedir + SUDO_DISK_TOOL_PATH),
        "rescan_iscsi_session"
    };
    if (Utils::CallAgentExecCmd(cmdParam, cmdOut) != 0) {
        ERRLOG("Failed to rescan device.");
    }
}

int32_t DiskScannerHandler::DetachVolume(const std::string &volId, const std::string &volWwn)
{
    bool ultraPathNotInstalled = false;
    if (g_installedUltr) {
        INFOLOG("UltraPath installed, no need to delete device!");
    } else {
        ultraPathNotInstalled = true;
    }
    bool isLoop = true;
    bool isExist = false;
    int nCycle = 0;
    while (ultraPathNotInstalled && isLoop && nCycle < DETACH_VOLUME_MAX_RETRY_TIMES) {
        isExist = false;
        std::vector<std::string> cmdOut;
        std::string agentHomedir = Module::EnvVarManager::GetInstance()->GetAgentHomePath();
        std::vector<Module::CmdParam> cmdParam {
            Module::CmdParam(Module::COMMON_CMD_NAME, "sudo"),
            Module::CmdParam(Module::SCRIPT_CMD_NAME, agentHomedir + SUDO_DISK_TOOL_PATH),
            "get_scsi_list"
        };
        if (Utils::CallAgentExecCmd(cmdParam, cmdOut) != 0) {
            ERRLOG("lsscsi command is not enable!");
            return Module::FAILED;
        }
        std::set<std::string> diskPathSet;
        diskPathSet.clear();
        for (const std::string& buff : cmdOut) { // 逐行读取，获取盘符
            std::string strLine(buff);
            int nPos = strLine.find("/dev/");
            if (nPos != -1) {
                strLine.erase(strLine.find_last_not_of("\n") + 1);
                strLine.erase(0, nPos);
                strLine.erase(strLine.end() - 1); // 去除最后一位空格
                diskPathSet.insert(strLine);
            }
        }
        int iRet = DeleteDiskFromPathSet(diskPathSet, volId, volWwn, isExist);
        if (!isExist) {
            isLoop = false;
        } else {
            return iRet;
        }
        nCycle++;
    }
    WARNLOG("Delete disk, not found from page volWwn:%s, id:%d", volWwn.c_str(), volId.c_str());
    return Module::SUCCESS;
}

int32_t DiskScannerHandler::DeleteDiskFromPathSet(std::set<std::string>& diskPathSet, const std::string& volId,
    const std::string& volWwn, bool& isExist)
{
    std::set<std::string>::iterator it;
    std::string agentHomedir = Module::EnvVarManager::GetInstance()->GetAgentHomePath();
    std::vector<string> diskPathVec(diskPathSet.begin(), diskPathSet.end());
    if (!ChangeFilePriviledge(diskPathVec, VolOpenMode::READ_ONLY)) {
        ERRLOG("Add o+r priviledge to diskPathSet failed.");
    }
    for (it = diskPathSet.begin(); it != diskPathSet.end(); ++it) {
        std::string strLunWWN;
        std::string strLunID;
        std::string strDiskPath = *it;
        GetDisk83Page(strDiskPath, strLunWWN, strLunID);
        DBGLOG("Disk path:%s, cur disk wwn:%s, id:%s, dest wwn:%s, id:%s", strDiskPath.c_str(), strLunWWN.c_str(),
            strLunID.c_str(), volWwn.c_str(), volId.c_str());
        if (strLunWWN == volWwn && strLunID == volId) {
            isExist = true;
            int nPos = strDiskPath.rfind("/");
            std::string strDiskName = strDiskPath.substr(nPos + 1);
            std::vector<std::string> cmdOut;
            std::unordered_set<std::string> pathWhitelist;
            pathWhitelist.insert(strDiskName);
            std::vector<Module::CmdParam> cmdParam {
                Module::CmdParam(Module::COMMON_CMD_NAME, "sudo"),
                Module::CmdParam(Module::SCRIPT_CMD_NAME, agentHomedir + SUDO_DISK_TOOL_PATH),
                "dev_delete",
                Module::CmdParam(Module::PATH_PARAM, strDiskName)
            };
            if (Utils::CallAgentExecCmd(cmdParam, cmdOut) != 0) {
                ERRLOG("Delete disk failed, path:%s", strDiskName.c_str());
                return Module::FAILED;
            }
            INFOLOG("Delete disk success, path:%s", strDiskName.c_str());
            return Module::SUCCESS;
        }
    }
    return Module::FAILED;
}

std::string DiskScannerHandler::FormatBaseUrl(const std::string &baseUrl) const
{
    uint32_t count = 0;
    for (uint32_t i = 0; i < baseUrl.length(); i++) {
        if (baseUrl[i] == ':') {
            count++;
        }
        if (count >= BASE_URL_SPLIT) {
            break;
        }
    }
    if (count <= 1) {
        return baseUrl;
    } else {
        std::size_t lastDelim = baseUrl.find_last_of(":");
        if (lastDelim == std::string::npos) {
            ERRLOG("Format base url seg not found");
            return baseUrl;
        }
        std::string ipstr = baseUrl.substr(0, lastDelim);
        std::string portstr = baseUrl.substr(lastDelim + 1);
        std::string ipv6str = "[" + ipstr + "]" + ":" + portstr;
        return ipv6str;
    }
}

std::string DiskScannerHandler::ScanDiskPreare(const std::string& volId, const std::string& volWwn)
{
    std::string diskPath = GetDiskPathForWWN(volWwn);
    std::string agentHomedir = Module::EnvVarManager::GetInstance()->GetAgentHomePath();
    if (diskPath.empty()) {
        WARNLOG("Get disk path for wwn failed, wait scan disk, wwn:%s, id:%s", volWwn.c_str(), volId.c_str());
    } else {
        INFOLOG("Get disk path for wwn success, path:%s,wwn:%s,id:%s", diskPath.c_str(), volWwn.c_str(),
            volId.c_str());
        return diskPath;
    }
    if (!g_installedUltr) {
        std::vector<std::string> cmdOut;
        std::vector<Module::CmdParam> cmdParam {
            Module::CmdParam(Module::COMMON_CMD_NAME, "sudo"),
            Module::CmdParam(Module::SCRIPT_CMD_NAME, agentHomedir + SUDO_DISK_TOOL_PATH),
            "check_upRescan"
        };
        if (Utils::CallAgentExecCmd(cmdParam, cmdOut) == 0) {
            INFOLOG("Installed UltraPath, wait scan disk.");
            g_installedUltr = true;
        }
    }
    if (GetScanState() == (int)RUNNING_UPRESCAN) {
        INFOLOG("Wait disk scaning ...");
        std::unique_lock<std::mutex> lock(g_scanLunMutex);
        g_scanlunEndCond.wait(lock, []() { return GetScanState() == (int)RUNNED_UPRESCAN; });
    } else {
        WARNLOG("upRescan not run, need scan disk.");
        return diskPath;
    }
    INFOLOG("Rescan disk end.");
    diskPath = GetDiskPathForWWN(volWwn);
    if (diskPath.empty()) {
        WARNLOG("Get disk path for wwn failed, exit and wait scan disk.");
    } else {
        INFOLOG("Get disk path for wwn success, path:");
    }
    return diskPath;
}

/**
 *  @brief 获取磁盘路径
 *
 *  @param volWwn   [IN] 磁盘WWN
 *  @return 成功返回磁盘路径，失败返回""
 */
std::string DiskScannerHandler::GetDiskPathForWWN(const std::string& volWwn)
{
    std::string diskPath;
    std::vector<std::string> cmdOut;
    std::string agentHomedir = Module::EnvVarManager::GetInstance()->GetAgentHomePath();
    std::vector<Module::CmdParam> cmdParam {
        Module::CmdParam(Module::COMMON_CMD_NAME, "sudo"),
        Module::CmdParam(Module::SCRIPT_CMD_NAME, agentHomedir + SUDO_DISK_TOOL_PATH),
        "get_diskpath_for_wwn",
        Module::CmdParam(Module::COMMON_PARAM, volWwn)
    };
    if (Utils::CallAgentExecCmd(cmdParam, cmdOut) != 0) {
        ERRLOG("The device is not found, path:%s", volWwn.c_str());
        return diskPath;
    }
    for (const auto& buff : cmdOut) {
        // buff样例：lrwxrwxrwx 1 root root  10 Apr 18 20:04 scsi-3620ab4810005746f32d1882500003735 -> ../../sdam
        std::string strLine(buff);
        std::string strLineCopy(buff);
        int nPos = strLine.find(D_FINDDISK);
        strLine.erase(strLine.find_last_not_of("\n") + 1);
        strLine.erase(0, nPos);
        strLine = "/dev/disk/by-id/" + strLine; // /dev/disk/by-id/../../sdam
        int nPosWWN = strLineCopy.find("scsi-");
        if (nPosWWN == -1) {
            nPosWWN = strLineCopy.find("wwn-");
            if (nPosWWN == -1) {
                continue;
            }
        }
        strLineCopy.erase(0, nPosWWN);
        int nPosSpace = strLineCopy.find(" ");
        strLineCopy.erase(nPosSpace);
        strLineCopy.erase(0, WWN_POS_OFFSET); // 620ab4810005746f32d1882500003735
        DBGLOG("Disk path:%s, line copy:%s", strLine.c_str(), strLineCopy.c_str());
        std::string strDiskWWN;
        std::string strDiskID;
        if (!ChangeFilePriviledge(strLine, VolOpenMode::READ_ONLY)) {
            ERRLOG("Add o+r priviledge to %s failed.", strLine.c_str());
        }
        GetDisk83Page(strLine, strDiskWWN, strDiskID);
        if (strDiskWWN == volWwn && strDiskWWN == strLineCopy) {
            DBGLOG("Get disk 83 page wwn is ok, wwn:%s, id:%s", strDiskWWN.c_str(), strDiskID.c_str());
            diskPath = strLine;
            RescanDevice(diskPath);
            break;
        }
    }
    return diskPath;
}

void DiskScannerHandler::RescanDevice(const std::string& diskPath)
{
    int nPos = diskPath.rfind("/");
    std::string strTemp = diskPath.substr(nPos + 1);
    std::string agentHomedir = Module::EnvVarManager::GetInstance()->GetAgentHomePath();
    DBGLOG("Exec rescan cmd: dev_rescan %s", strTemp.c_str());
    std::vector<std::string> cmdOut;
    std::unordered_set<std::string> pathWhitelist;
    pathWhitelist.insert(strTemp);
    std::vector<Module::CmdParam> cmdParam {
        Module::CmdParam(Module::COMMON_CMD_NAME, "sudo"),
        Module::CmdParam(Module::SCRIPT_CMD_NAME, agentHomedir + SUDO_DISK_TOOL_PATH),
        "dev_rescan",
        Module::CmdParam(Module::PATH_PARAM, strTemp)
    };
    Utils::CallAgentExecCmd(cmdParam, cmdOut);
}

std::string DiskScannerHandler::GetDiskPath(const std::string& volId, const std::string& volWwn)
{
    std::string diskPath = GetDiskPathForWWN(volWwn);
    if (!diskPath.empty()) {
        INFOLOG("Get disk path for wwn success, wwn:%s, id:%s,path:%s",
            volWwn.c_str(), volId.c_str(), diskPath.c_str());
        return diskPath;
    }
    int nCycle = 0;
    bool isLoop = false;
    do {
        nCycle++;
        std::map<std::string, std::set<std::string>> diskPathMap;
        diskPathMap.clear();
        if (GetDiskPathMap(diskPathMap) != Module::SUCCESS) {
            return diskPath;
        }
        bool ultraPathNotInstalled = false;
        if (g_installedUltr) {
            INFOLOG("UltraPath installed, no need to delete scsi_device");
        } else {
            ultraPathNotInstalled = true;
        }
        if (GetDiskPathInner(diskPathMap, volWwn, diskPath, ultraPathNotInstalled, isLoop) == Module::SUCCESS) {
            return diskPath;
        }
    } while (isLoop && nCycle < MAX_CYCLE_NUM);
    return diskPath;
}

int32_t DiskScannerHandler::GetDiskPathMap(std::map<std::string, std::set<std::string>>& diskPathMap)
{
    std::string agentHomedir = Module::EnvVarManager::GetInstance()->GetAgentHomePath();
    std::vector<std::string> cmdOut;
    std::vector<Module::CmdParam> cmdParam {
        Module::CmdParam(Module::COMMON_CMD_NAME, "sudo"),
        Module::CmdParam(Module::SCRIPT_CMD_NAME, agentHomedir + SUDO_DISK_TOOL_PATH),
        "get_diskpath_list"
    };
    if (Utils::CallAgentExecCmd(cmdParam, cmdOut) != 0) {
        ERRLOG("ls -al /dev/disk/by-id command is not enable!");
        return Module::FAILED;
    }
    for (const std::string& buff : cmdOut) { // 逐行读取，获取盘符
        std::string strLine(buff);
        std::string strLineCopy(buff);
        int nPos = strLine.find(D_FINDDISK);
        if (nPos == std::string::npos) {
            continue;
        }
        strLine.erase(strLine.find_last_not_of("\n") + 1); // 去除分区干扰
        INFOLOG("Line:%s", strLine.c_str());
        strLine.erase(0, nPos);
        strLine = "/dev/disk/by-id/" + strLine;
        int nPosWWN = strLineCopy.find("scsi-");
        if (nPosWWN == -1) {
            nPosWWN = strLineCopy.find("wwn-");
            if (nPosWWN == -1) {
                continue;
            }
        }
        int offset = WWN_POS_OFFSET;
        strLineCopy.erase(0, nPosWWN);
        int nPosSpace = strLineCopy.find(" ");
        strLineCopy.erase(nPosSpace);
        strLineCopy.erase(0, offset);
        std::map<std::string, std::set<std::string>>::iterator diskMapIt = diskPathMap.find(strLine);
        std::set<std::string> pathSet;
        if (diskMapIt != diskPathMap.end()) {
            pathSet = diskMapIt->second;
        }
        pathSet.insert(strLineCopy);
        diskPathMap[strLine] = pathSet;
    }
    return Module::SUCCESS;
}

int32_t DiskScannerHandler::GetDiskPathInner(std::map<std::string, std::set<std::string>>& diskPathMap,
    const std::string& volWwn, std::string& diskPath, const bool& ultraPathNotInstalled, bool& isLoop)
{
    diskPath = "";
    std::string agentHomedir = Module::EnvVarManager::GetInstance()->GetAgentHomePath();
    std::vector<std::string> diskPathVec;
    std::transform(diskPathMap.begin(), diskPathMap.end(), std::back_inserter(diskPathVec), [](const auto &pair) { return pair.first; });
    if (!ChangeFilePriviledge(diskPathVec, VolOpenMode::READ_ONLY)) {
        ERRLOG("Add o+r priviledge to diskPathMap failed.");
    }
    for (std::map<std::string, std::set<std::string>>::iterator it = diskPathMap.begin(); it != diskPathMap.end(); ++it) {
        std::string strDiskWWN;
        std::string strDiskID;
        std::string strDiskPath = it->first;
        GetDisk83Page(strDiskPath, strDiskWWN, strDiskID);
        DBGLOG("Disk path: %s, target wwn: %s, 83 page wwn: %s", strDiskPath.c_str(), volWwn.c_str(), strDiskWWN.c_str());
        std::set<std::string>::iterator pathSetIt = it->second.begin();
        for (; pathSetIt != it->second.end(); ++pathSetIt) {
            if (strDiskWWN != volWwn || strDiskWWN != *pathSetIt) {
                DBGLOG("Target wwn: %s, 83 page wwn: %s, path set it: %s, wwn not equals, continue to find next path.",
                    volWwn.c_str(), strDiskWWN.c_str(), (*pathSetIt).c_str());
                continue;
            }
            diskPath = it->first;
            int nPos = diskPath.rfind("/");
            std::string strTemp = diskPath.substr(nPos + 1);
            DBGLOG("Find target wwn: %s, disk path: %s", volWwn.c_str(), strTemp.c_str());
            if (DevRescan(strTemp) != Module::SUCCESS) {
                ERRLOG("Dev rescan failed, disk path: %s", strTemp.c_str());
                return Module::FAILED;
            }
            DBGLOG("Exec /sys/block%s/device/rescan", strTemp.c_str());
            return Module::SUCCESS;
        }
        if (ultraPathNotInstalled && strDiskWWN == volWwn) {
            std::string strDiskName("");
            WARNLOG("Disk path: %s, only 83 page wwn equals target wwn: %s", strDiskPath.c_str(), volWwn.c_str());
            if (GetDiskName(diskPath, strDiskName, it->first) != Module::SUCCESS || DeleteAndScanHost(strDiskName) != Module::SUCCESS) {
                return Module::FAILED;
            }
            // 删除了dev的情况下，diskPath需要重新获取
            diskPath = "";
            isLoop = true;
        }
    }
    return Module::FAILED;
}

int32_t DiskScannerHandler::DevRescan(const std::string &devPath)
{
    std::string agentHomedir = Module::EnvVarManager::GetInstance()->GetAgentHomePath();
    std::vector<std::string> cmdOut;
    DBGLOG("Dev rescan, disk path: %s", devPath.c_str());
    std::vector<Module::CmdParam> cmdParam {
        Module::CmdParam(Module::COMMON_CMD_NAME, "sudo"),
        Module::CmdParam(Module::SCRIPT_CMD_NAME, agentHomedir + SUDO_DISK_TOOL_PATH),
        "dev_rescan",
        Module::CmdParam(Module::COMMON_PARAM, devPath)
    };
    if (Utils::CallAgentExecCmd(cmdParam, cmdOut) != 0) {
        ERRLOG("Exec /sys/block%s/device/rescan failed.", devPath.c_str());
        return Module::FAILED;
    }
    DBGLOG("Exec /sys/block%s/device/rescan success.", devPath.c_str());
    return Module::SUCCESS;
}

int32_t DiskScannerHandler::GetDiskName(std::string& diskPath, std::string& strDiskName, const std::string& strDiskPath)
{
    diskPath = strDiskPath;
    int nDmPos = diskPath.find("dm");
    int nSdmPos = diskPath.find("sdm"); // 排除sdm的干扰
    std::string agentHomedir = Module::EnvVarManager::GetInstance()->GetAgentHomePath();
    if (nDmPos != -1 && nSdmPos == -1) {
        DBGLOG("Disk path: %s, name contain dm.", diskPath.c_str());
        std::vector<std::string> cmdOut;
        std::vector<Module::CmdParam> cmdParam {
            Module::CmdParam(Module::COMMON_CMD_NAME, "sudo"),
            Module::CmdParam(Module::SCRIPT_CMD_NAME, agentHomedir + SUDO_DISK_TOOL_PATH),
            "do_multipath"
        };
        if (Utils::CallAgentExecCmd(cmdParam, cmdOut) != 0) {
            ERRLOG("multipath -ll is not enable!");
            return Module::FAILED;
        }
        for (const auto& dmBuff : cmdOut) {
            std::string strTmpLine(dmBuff);
            diskPath = strDiskPath;
            int nPos = diskPath.rfind("/");
            std::string strTempDisk = diskPath.substr(nPos + 1);
            nPos = strTmpLine.find(strTempDisk);
            if (nPos == -1) {
                continue;
            }
            strTmpLine = dmBuff;
            nPos = strTmpLine.find("sd");
            if (nPos != -1) {
                std::string strTmp = strTmpLine.erase(0, nPos);
                nPos = strTmp.find(" ");
                strDiskName = strTmp.substr(0, nPos);
                strDiskName = "/dev/" + strDiskName;
            }
        }
        DBGLOG("Disk name: %s", strDiskName.c_str());
    } else {
        int nPos = diskPath.rfind("/");
        std::string strTemp = diskPath.substr(nPos);
        strDiskName = "/dev" + strTemp;
        DBGLOG("Disk path: %s, name not contain dm, disk name: %s", diskPath.c_str(), strDiskName.c_str());
    }
    return Module::SUCCESS;
}

int32_t DiskScannerHandler::DeleteAndScanHost(const std::string& strDiskName)
{
    std::vector<std::string> cmdOut;
    std::string agentHomedir = Module::EnvVarManager::GetInstance()->GetAgentHomePath();
    std::vector<Module::CmdParam> cmdParam {
        Module::CmdParam(Module::COMMON_CMD_NAME, "sudo"),
        Module::CmdParam(Module::SCRIPT_CMD_NAME, agentHomedir + SUDO_DISK_TOOL_PATH),
        "get_scsi_list"
    };
    if (Utils::CallAgentExecCmd(cmdParam, cmdOut) != 0) {
        return Module::FAILED;
    }
    for (const std::string& buff : cmdOut) {
        std::string strLine(buff);
        std::string strHostFirst;
        std::string strHostLast;
        DBGLOG("Get scsi list path: %s", strLine.c_str());
        int nPos = strLine.find(strDiskName);
        if (nPos == -1) {
            continue;
        }
        int nFirstPos = strLine.find("[");
        int nLastPos = strLine.find("]");
        if (nFirstPos == -1 || nLastPos == -1 || nFirstPos > nLastPos) {
            continue;
        }
        std::string strHost = strLine.substr(nFirstPos + 1, nLastPos - 1);
        nPos = strHost.find(":");
        strHostFirst = strHost.substr(0, nPos);
        nPos = strHost.find_last_of(":");
        std::string strTmp = strHost;
        strHostLast = strTmp.erase(0, nPos + 1);
        if (strHostLast == "0") {
            continue;
        }
        DeleteScsiAndScanHost(strHost, strHostFirst);
        sleep(1);
    }
    return Module::SUCCESS;
}

void DiskScannerHandler::DeleteScsiAndScanHost(const std::string &strHost, const std::string &strHostFirst)
{
    std::string agentHomedir = Module::EnvVarManager::GetInstance()->GetAgentHomePath();
    std::vector<std::string> cmdOut;
    std::vector<Module::CmdParam> cmdParam {
        Module::CmdParam(Module::COMMON_CMD_NAME, "sudo"),
        Module::CmdParam(Module::SCRIPT_CMD_NAME, agentHomedir + SUDO_DISK_TOOL_PATH),
        "scsi_delete",
        Module::CmdParam(Module::COMMON_PARAM, strHost)
    };
    Utils::CallAgentExecCmd(cmdParam, cmdOut);
    cmdParam.clear();
    cmdOut.clear();
    cmdParam = {
        Module::CmdParam(Module::COMMON_CMD_NAME, "sudo"),
        Module::CmdParam(Module::SCRIPT_CMD_NAME, agentHomedir + SUDO_DISK_TOOL_PATH),
        "host_scan",
        Module::CmdParam(Module::COMMON_PARAM, strHostFirst)
    };
    Utils::CallAgentExecCmd(cmdParam, cmdOut);
}

/**
 *  @brief 获取83页信息
 *
 *  @param strDevice   [IN]设备名
 *  @param strLunWWN   [OUT]LUN的WWN
 *  @param strLunID    [OUT]LUN的ID
 *  @return 成功返回 SUCCESS，出错返回 Module::FAILED
 */
int32_t DiskScannerHandler::GetDisk83Page(const std::string& strDevice, std::string& strLunWWN, std::string& strLunID)
{
    if (strDevice.empty()) {
        ERRLOG("Get disk 83 page failed, device is empty!");
        return Module::FAILED;
    }
    unsigned char aucBuffer[DATA_LEN_256] = {0};
    char acLUNWWN[MAX_WWN_LEN] = {0};
    int iFd = open(strDevice.c_str(), O_RDONLY | O_NONBLOCK); // 打开scsi设备
    if (iFd < 0) {
        ERRLOG("Open disk 83 page failed, errno[%d]:[%s]", errno, strerror(errno));
        close(iFd);
        return Module::FAILED;
    }
    int iRet = GetDiskPage(iFd, PAGE_83, aucBuffer);
    if (iRet != Module::SUCCESS) {
        close(iFd);
        return iRet;
    }
    int iPageLen = aucBuffer[PAGE_LEN_IDX];
    if (iPageLen * MULTIPLE > MAX_WWN_LEN - 1) {
        close(iFd);
        ERRLOG("Open disk 83 page failed, err page len:%d", iPageLen);
        return Module::FAILED;
    }
    int nLength = BINARY_TO_ASCII_LEN;
    iRet = BinaryToAscii(acLUNWWN, MAX_WWN_LEN, aucBuffer, nLength, iPageLen); // 阵列WWN
    if (iRet != Module::SUCCESS) {
        close(iFd);
        ERRLOG("Binary to ascii failed!");
        return iRet;
    }
    strLunWWN = acLUNWWN;
    unsigned char acHexData[MAX_LUNID_LEN] = {0};
    char acDevLUNID[MAX_LUNID_LEN] = {0}; // LUN ID
    int nLen = LUN_ID_TO_ASCII_LEN;
    int nOffset = LUN_ID_TO_ASCII_OFFSET;
    iRet = ConvertLunIdToAscii(acHexData, MAX_LUNID_LEN, aucBuffer + nOffset, nLen);
    if (iRet != Module::SUCCESS) {
        close(iFd);
        ERRLOG("Convert lun id to ascii failed!");
        return iRet;
    }
    close(iFd);
    (void)HextoDec(acDevLUNID, (char*)acHexData, MAX_LUNID_LEN);
    strLunID = acDevLUNID;
    return Module::SUCCESS;
}

/**
 *  @brief 更改文件权限
 *
 *  @param file        [IN]待更改的文件名称
 *  @param mode        [IN]]更改模式
 *  @return 成功返回 true，出错返回 false
 */
bool DiskScannerHandler::ChangeFilePriviledge(const std::string &file, const VolOpenMode &mode)
{
    std::string modeStr;
    std::string agentHomedir = Module::EnvVarManager::GetInstance()->GetAgentHomePath();
    modeStr = mode == VolOpenMode::READ_WRITE ? "o+w" : "o+r";
    std::vector<std::string> cmdOut;
    std::vector<Module::CmdParam> cmdParam {
        Module::CmdParam(Module::COMMON_CMD_NAME, "sudo"),
        Module::CmdParam(Module::SCRIPT_CMD_NAME, agentHomedir + SUDO_DISK_TOOL_PATH),
        "change_priviledge",
        Module::CmdParam(Module::COMMON_PARAM, modeStr),
        Module::CmdParam(Module::PATH_PARAM, file)
    };
    if (Utils::CallAgentExecCmd(cmdParam, cmdOut) != 0) {
        ERRLOG("Add %s priviledge to %s failed.", modeStr.c_str(), file.c_str());
        return false;
    }
    INFOLOG("Add %s priviledge to %s success.", modeStr.c_str(), file.c_str());
    return true;
}

/**
 *  @brief 批量文件权限
 *
 *  @param file        [IN]待更改的文件列表名称
 *  @param mode        [IN]]更改模式
 *  @return 成功返回 true，出错返回 false
 */
bool DiskScannerHandler::ChangeFilePriviledge(const std::vector<std::string> &files, const VolOpenMode &mode)
{
    std::string modeStr;
    std::string agentHomedir = Module::EnvVarManager::GetInstance()->GetAgentHomePath();
    modeStr = mode == VolOpenMode::READ_WRITE ? "o+w" : "o+r";
    std::vector<std::string> cmdOut;
    std::vector<Module::CmdParam> cmdParam {
        Module::CmdParam(Module::COMMON_CMD_NAME, "sudo"),
        Module::CmdParam(Module::SCRIPT_CMD_NAME, agentHomedir + SUDO_DISK_TOOL_PATH),
        "change_priviledge",
        Module::CmdParam(Module::COMMON_PARAM, modeStr),
    };
    cmdParam.reserve(cmdParam.size() + files.size());

    for (auto &file : files) {
        cmdParam.emplace_back(Module::PATH_PARAM, file);
        DBGLOG("Add %s to change priviledge file list", file.c_str());
    }

    if (Utils::CallAgentExecCmd(cmdParam, cmdOut) != 0) {
        ERRLOG("Add %s priviledge file list failed.", modeStr.c_str());
        return false;
    }
    INFOLOG("Add %s priviledge to file list success.", modeStr.c_str());
    return true;
}

/**
 *  @brief 获取80和83页信息
 *
 *  @param iFd          [IN]设备描述符
 *  @param ucCmd        [OUT]80,83页标识
 *  @param aucBuffer    [OUT]80,83页信息
 *  @return 成功返回 SUCCESS，出错返回 Module::FAILED
 */
int32_t DiskScannerHandler::GetDiskPage(int iFd, unsigned char ucCmd, unsigned char* aucBuffer)
{
    if (aucBuffer == nullptr) {
        ERRLOG("Get disk page failed, aucBuffer is empty!");
        return Module::FAILED;
    }
    unsigned char aucCdb[CDB6GENERIC_LENGTH] = {0};
    // 初始化CDB
    int cmdOffset = CMD_OFFSET;
    int trdOffset = TRD_OFFSET;
    int nextOffset = NEXT_OFFSET;
    int defaultVal = DEFAULT_VAL;
    aucCdb[0] = SCSIOP_INQUIRY;
    aucCdb[1] = 0x01;
    aucCdb[cmdOffset] = ucCmd;
    aucCdb[trdOffset] = 0;
    aucCdb[nextOffset] = defaultVal;
    sg_io_hdr_t ioHdr;
    unsigned char aucSense[SCSI_MAX_SENSE_LEN] = {0};
    // 初始化sg_io_hdr_t
    if (memset_s(&ioHdr, sizeof(sg_io_hdr_t), 0, sizeof(sg_io_hdr_t)) != EOK) {
        ERRLOG("Get disk page failed, memset_s failed!");
        return Module::FAILED;
    }
    ioHdr.interface_id = 'S';
    ioHdr.cmdp = aucCdb;
    ioHdr.cmd_len = CDB6GENERIC_LENGTH;
    ioHdr.sbp = aucSense;
    ioHdr.mx_sb_len = SCSI_MAX_SENSE_LEN;
    ioHdr.dxfer_direction = SG_DXFER_FROM_DEV;
    ioHdr.dxferp = aucBuffer;
    ioHdr.dxfer_len = DATA_LEN_256;
    ioHdr.timeout = SCSI_CMD_TIMEOUT_LINUX;
    int iRet = ioctl(iFd, SG_IO, &ioHdr);
    if (iRet != Module::SUCCESS || ioHdr.status != 0) {
        ERRLOG("Get disk page failed, ioctl failed, ret:%d, status:%d, errno[%d]:[%s]", iRet, ioHdr.status, errno,
            strerror(errno));
        return Module::FAILED;
    }
    return Module::SUCCESS;
}

int32_t DiskScannerHandler::BinaryToAscii(char* pszHexBuffer, int iBufferLen, unsigned char* pucBuffer, int iStartBuf,
    int iLength)
{
    if (pucBuffer == nullptr) {
        ERRLOG("Binary to ascii failed, pucBuffer is empty!");
        return Module::FAILED;
    }
    if (pszHexBuffer == nullptr) {
        ERRLOG("Binary to ascii failed, pszHexBuffer is empty!");
        return Module::FAILED;
    }
    if (iBufferLen - 1 < iLength * MULTIPLE) {
        return Module::FAILED;
    }
    for (int iBuffLen = 0; iBuffLen < iLength; iBuffLen++) {
        if (sprintf_s(&pszHexBuffer[iBuffLen * MULTIPLE], iBufferLen - iBuffLen * MULTIPLE, "%02x",
            pucBuffer[iBuffLen + iStartBuf]) == -1) {
            return Module::FAILED;
        }
    }
    return Module::SUCCESS;
}

int32_t DiskScannerHandler::ConvertLunIdToAscii(unsigned char* puszAsciiLunID, int iBufferLen,
    unsigned char* puszLunLunID, int iLen)
{
    if ((puszAsciiLunID == nullptr)) {
        ERRLOG("Convert lun id to ascii failed, puszAsciiLunID is empty!");
        return Module::FAILED;
    }
    if (puszLunLunID == nullptr) {
        ERRLOG("Convert lun id to ascii failed, puszLunLunID is empty!");
        return Module::FAILED;
    }
    if (iBufferLen - 1 < iLen) {
        return Module::FAILED;
    }
    int32_t num = MULTIPLE;
    for (int iCount = 0; iCount < iLen / num; iCount++) {
        if (sprintf_s((char*)&puszAsciiLunID[iCount * MULTIPLE], iBufferLen - iCount * MULTIPLE, "%02x",
            puszLunLunID[iCount]) == -1) {
            return Module::FAILED;
        }
    }
    return Module::SUCCESS;
}

int32_t DiskScannerHandler::HextoDec(char* pDecStr, char* pHexStr, int iMaxLen)
{
    int iStrLen = 0;
    int iStep = 0;
    int iDecNum = 0;
    if (pDecStr == nullptr) {
        ERRLOG("Hex to dec failed, pDecStr is empty!");
        return Module::FAILED;
    }
    if (pHexStr == nullptr) {
        ERRLOG("Hex to dec failed, pHexStr is empty!");
        return Module::FAILED;
    }
    iStrLen = (int)strlen(pHexStr);
    for (int iTemp = 0; iTemp < iStrLen; iTemp++) {
        iStep = (iStrLen - iTemp) - 1;
        if (pHexStr[iTemp] == '0') {
            continue;
        } else if ((pHexStr[iTemp] > '0') && (pHexStr[iTemp] <= '9')) {
            iDecNum = iDecNum + (pHexStr[iTemp] - ASCII_BASE) * CalStep(iStep);
        } else if (((pHexStr[iTemp] >= 'a') && (pHexStr[iTemp] <= 'f')) ||
                   ((pHexStr[iTemp] >= 'A') && (pHexStr[iTemp] <= 'F'))) {
            (void)HexEncode(pHexStr[iTemp], iStep, iDecNum);
        } else {
            return Module::FAILED;
        }
    }
    if (snprintf_s(pDecStr, (unsigned int)iMaxLen, (unsigned int)iMaxLen - 1, "%d", iDecNum) == -1) {
        ERRLOG("Hex to dec failed, snprintf_s failed!");
        return Module::FAILED;
    }
    return Module::SUCCESS;
}

int32_t DiskScannerHandler::HexEncode(char cHex, int iStep, int& iDecNum)
{
    switch (cHex) {
        case 'a':
        case 'A': {
            iDecNum = iDecNum + DEC_A * CalStep(iStep);
            break;
        }
        case 'b':
        case 'B': {
            iDecNum = iDecNum + DEC_B * CalStep(iStep);
            break;
        }
        case 'c':
        case 'C': {
            iDecNum = iDecNum + DEC_C * CalStep(iStep);
            break;
        }
        case 'd':
        case 'D': {
            iDecNum = iDecNum + DEC_D * CalStep(iStep);
            break;
        }
        case 'e':
        case 'E': {
            iDecNum = iDecNum + DEC_E * CalStep(iStep);
            break;
        }
        case 'f':
        case 'F': {
            iDecNum = iDecNum + DEC_F * CalStep(iStep);
            break;
        }
        default:
            return Module::FAILED;
    }
    return Module::SUCCESS;
}

/**
 *  @brief 计算16进制指数值
 *
 *  @param iStep        [IN]16进制指数值
 *  @return 返回 返回计算结果
 */
int32_t DiskScannerHandler::CalStep(int iStep) const
{
    int hexNum = HEX_NUM;
    int iResult = 1;
    while (iStep > 0) {
        iResult = iResult * hexNum;
        iStep--;
    }
    return iResult;
}
}